package com.paradise.rsasign.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 文件 hash 工具类
 */
@Slf4j
public class FileHashUtils {
    private FileHashUtils() {
        throw new IllegalStateException();
    }

    /**
     * 获取文件 sha256 hash
     *
     * @param file 文件
     * @return byte[] sha256 hash
     * @throws IOException IO 异常
     */
    public static byte[] hashWithSha256(File file) throws IOException {

        try (FileInputStream inputStream = new FileInputStream(file)) {
            byte[] buffer = new byte[1024];
            try {
                MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
                for (int r; (r = inputStream.read(buffer)) > 0; ) {
                    messageDigest.update(buffer, 0, r);
                }
                return messageDigest.digest();
            } catch (NoSuchAlgorithmException | FileNotFoundException e) {
                log.error(e.getLocalizedMessage(), e);
            }
        }
        return new byte[]{};
    }

    /**
     * 获取文件 sha256 hash
     *
     * @param file 文件
     * @return sha256 hash
     * @throws IOException IO 异常
     */
    public static String hashFileWithSha256(File file) throws IOException {
        return toHexStr(hashWithSha256(file));
    }

    /**
     * byte[] 转 16进制字符串
     *
     * @param bytes byte[] 数组
     * @return 16 进制字符串
     */
    private static String toHexStr(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder();
        for (byte b : bytes) {
            // 不同的写法：" stringBuilder.append(Integer.toHexString(b & 0XFF));"
            stringBuilder.append(String.format("%02x", b));
        }
        return stringBuilder.toString();

    }

    private static String getFileType(File file) {
        String fileName = file.getName();
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    private static String encodeUrl(String url) {
        try {
            return URLEncoder.encode(url, StandardCharsets.UTF_8.displayName());
        } catch (UnsupportedEncodingException ignore) {
            // 忽略
        }
        return null;
    }

    public static String getFileFormatProperty(File file, String url) throws IOException {
        return "file:" + encodeUrl(url) + ":" + getFileType(file) + ":" + hashFileWithSha256(file) + ":sha256";
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        // 文件地址
        //http://146.56.245.24:56082/cer.pdf

        // 地址 url encode 方法
        String url = "http://146.56.245.24:56082/cer.pdf";
        final String urlEncode = URLEncoder.encode(url, StandardCharsets.UTF_8.displayName());
        System.out.println(urlEncode);

        String oUrl = "http%3A%2F%2F146.56.245.24%3A56082%2Fcer.pdf";
        System.out.println(oUrl.equals(urlEncode));

        // 文件 hash 验证
        final String dir = System.getProperty("user.dir");
        System.out.println("当前目录：" + dir);
        File file = new File(dir, "cer.pdf");

        try {
            final String sha256 = hashFileWithSha256(file);
            System.out.println(sha256);
            String oh = "7cf647225ed0259b31e9876e4c25ee141827680c82bfa32aa7c01f4dd0c00698";
            System.out.println(sha256.equalsIgnoreCase(oh));

            // 生成 完整的文件上链格式
            // 字段格式规范是 file:[encode url]:[file type]:[hash]:[hash type] \n (hash type: sha256;file type: pdf/jpg）
            // url 必须支持跨域访问，否则无法核验
            final String fileFormatProperty = getFileFormatProperty(file, url);
            System.out.println(fileFormatProperty);
            String result = "file:http%3A%2F%2F146.56.245.24%3A56082%2Fcer.pdf:pdf:7cf647225ed0259b31e9876e4c25ee141827680c82bfa32aa7c01f4dd0c00698:sha256";
            System.out.println(result.equals(fileFormatProperty));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
